﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace MTGenome.UI
{
    /// <summary>
    /// Class that can add easy gridline snapping to child elements
    /// </summary>
    public class SnappingCanvas : Canvas
    {
        #region IsSnappingEnabled

        /// <summary>
        /// IsSnappingEnabled Dependency Property
        /// </summary>
        public static readonly DependencyProperty IsSnappingEnabledProperty =
            DependencyProperty.Register("IsSnappingEnabled", typeof(bool), typeof(SnappingCanvas),
                new FrameworkPropertyMetadata((bool)true));

        /// <summary>
        /// Gets or sets the IsSnappingEnabled property.  This dependency property 
        /// indicates if snapping is turned on or not.
        /// </summary>
        public bool IsSnappingEnabled
        {
            get { return (bool)GetValue(IsSnappingEnabledProperty); }
            set { SetValue(IsSnappingEnabledProperty, value); }
        }

        #endregion

        #region SnapDistance

        /// <summary>
        /// SnapDistance Dependency Property
        /// </summary>
        public static readonly DependencyProperty SnapDistanceProperty =
            DependencyProperty.Register("SnapDistance", typeof(double), typeof(SnappingCanvas),
                new FrameworkPropertyMetadata((double)5,
                    new PropertyChangedCallback(OnSnapDistanceChanged)));

        /// <summary>
        /// Gets or sets the SnapDistance property.  This dependency property 
        /// indicates the pixel value at which snapping occurs.
        /// </summary>
        public double SnapDistance
        {
            get { return (double)GetValue(SnapDistanceProperty); }
            set { SetValue(SnapDistanceProperty, value); }
        }

        /// <summary>
        /// Handles changes to the SnapDistance property.
        /// </summary>
        private static void OnSnapDistanceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((SnappingCanvas)d).OnSnapDistanceChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the SnapDistance property.
        /// </summary>
        protected virtual void OnSnapDistanceChanged(DependencyPropertyChangedEventArgs e)
        {
            CoerceForSnapping(this, LeftProperty);
            CoerceForSnapping(this, TopProperty);
        }

        #endregion

        static SnappingCanvas()
        {
            LeftProperty.OverrideMetadata(typeof(SnappingCanvas),
                new FrameworkPropertyMetadata(0d, null, new CoerceValueCallback(CoerceForSnapping)));

            TopProperty.OverrideMetadata(typeof(SnappingCanvas),
                new FrameworkPropertyMetadata(0d, null, new CoerceValueCallback(CoerceForSnapping)));
        }

        private static object CoerceForSnapping(DependencyObject d, object value)
        {
            SnappingCanvas canvas = (SnappingCanvas)d;
            if (canvas.IsSnappingEnabled)
            {
                return (double)value - (double)value % canvas.SnapDistance;
            }
            else
            {
                return value;
            }
        }
    }
}
